package com.redis.RedisConfigProxy;

/**
 * @description: TODO
 * @date 2021/10/15 11:03
 */

import com.alibaba.fastjson.JSONObject;
import com.redis.config.RedisKeyExpirationListener;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Redis 发布订阅自动配置
 */
@Configuration
@EnableCaching
public class RedisListenAutoConfig implements BeanPostProcessor {

    private static  RedisMessageListenerContainer container = new RedisMessageListenerContainer();


    @Bean
    public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
        container.setConnectionFactory(connectionFactory);
        return container;
    }



    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 扫描订阅
        scannerRedisSubscribe(bean);
        return bean;
    }

    private void scannerRedisSubscribe(Object bean) {
        List<RedisListenInfo> redisListenInfoList = getRedisListenInfo(bean);
        if (redisListenInfoList != null) {
            addRedisListener(redisListenInfoList);
        }
    }

    // 获取Redis订阅所需要的用到的信息,【对象,方法,订阅主题】
    public List<RedisListenInfo> getRedisListenInfo(Object obj) {
        Method[] allDeclaredMethods = ReflectionUtils.getAllDeclaredMethods(obj.getClass());
        return Arrays.stream(allDeclaredMethods)
                .filter(m -> m.isAnnotationPresent(RedisSubscribe.class)).map(m -> {
                    RedisSubscribe annotation = m.getAnnotation(RedisSubscribe.class);
                    RedisListenInfo redisListenInfo = new RedisListenInfo();
                    redisListenInfo.setObject(obj);
                    redisListenInfo.setTopic(Arrays.stream(annotation.value()).map(ChannelTopic::new).collect(Collectors.toList()));
                    redisListenInfo.setMethod(m);
                    redisListenInfo.setParameterTypes(Arrays.asList(m.getParameterTypes()));
                    return redisListenInfo;
                }).collect(Collectors.toList());
    }


    // 通过jdk动态代理实现MessageListener
    private void addRedisListener(List<RedisListenInfo> redisListenInfo) {
        System.out.println(JSONObject.toJSONString(redisListenInfo));
        redisListenInfo.forEach(d -> {
            MessageListener messageListener = (MessageListener) Proxy.newProxyInstance(
                    RedisListenAutoConfig.class.getClassLoader(),
                    new Class[]{MessageListener.class},
                    new MessageListenInvocationHandler(d));
            container.addMessageListener(messageListener, d.getTopic());
        });
    }


}